﻿using System;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using DVDFilmoteka.Settings;
using MovieStorage;

namespace DVDFilmoteka.ServerDatabaseManagement
{
    class IMDBServerDatabase : IServerDatabase
    {
        #region constants

        private const String SERVERADDRESS = "http://www.imdb.com";
        private const String SERVERSEARCHPATH = "/find";
        private const String SERVERQUERY = "q";
        private const String USERAGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
        private const String XMLPATH_SEARCHRESULTS = "//a[text()='{0}']";
        private const String XMLPATH_SEARCHRESULTS2 = "//a[contains(text(),'{0}')]";

        private const String HODNOCENI_XPATH = "//div[@class='general rating']/div[@class='meta']/b";
        private const String MAINTITLE_XPATH = "//div[@id='tn15title']/h1";
        
        #endregion


        /// <summary>
        /// Vrati adresu stranky s konkretnim filmem
        /// </summary>
        /// <returns>Adresa stranky s filmem</returns>
        private String getFilmPage(String filmName)
        {
            if (string.IsNullOrEmpty(filmName)) return null;

            if (filmName.Contains(", The"))
            {
                filmName = filmName.Substring(0, filmName.Length - 5);
            }

            // Ziskat stranku ze serveru
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.QueryString.Add(SERVERQUERY, filmName);
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.UseProxy)
            {
                if (!SettingsManager.Instance.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.ProxyPort);
                    client.Proxy = proxy;
                }
                else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }

            byte[] data;
            try
            {
                data = client.DownloadData(SERVERADDRESS + SERVERSEARCHPATH);
            }
            catch (Exception e)
            {
                MessageBox.Show("Během přístupu k serveru došlo k vyjímce: " + e.Message);
                return null;
            }
            String readData = client.Encoding.GetString(data);
            readData = readData.ToLower();

            // Prevest HTML stranku na XML
            XmlDocument document = convertHtmlToXml(readData);

            String redirect = null;
            String xpath = MAINTITLE_XPATH;
            XmlNodeList seznamUzlu2 = document.SelectNodes(xpath);
            if (seznamUzlu2 != null && seznamUzlu2.Count > 0) //Rovnou presmerovano
            {
                redirect = SERVERSEARCHPATH + "?" + SERVERQUERY + "=" + filmName;
            }
            else
            {
                // Vyhledat odkaz na stranku s filmem
                xpath = String.Format(XMLPATH_SEARCHRESULTS, filmName).ToLower();
                XmlNodeList seznamUzlu = document.SelectNodes(xpath);
                if (seznamUzlu == null || seznamUzlu.Count <= 0)
                {
                    xpath = String.Format(XMLPATH_SEARCHRESULTS2, filmName).ToLower();
                    seznamUzlu = document.SelectNodes(xpath);
                    if (seznamUzlu == null || seznamUzlu.Count <= 0)
                    {
                        return null;
                    }
                }
                
                // Prhlidnout vsechny nody a najit ten spravny
                foreach (XmlNode uzel in seznamUzlu)
                {
                    if (uzel.Attributes.GetNamedItem("href") != null &&
                        !String.IsNullOrEmpty(uzel.Attributes.GetNamedItem("href").Value))
                    {
                        redirect = uzel.Attributes.GetNamedItem("href").Value;
                        break;
                    }
                }

                if (redirect != null && redirect.Contains("/board"))
                {
                    redirect = redirect.Substring(0, redirect.Length - "/board".Length);
                }
            }
            
            if (String.IsNullOrEmpty(redirect)) return null;

            return SERVERADDRESS + redirect;
        }

        #region IServerDatabase Members

        /// <summary>
        /// Nacte udaje o filmu podle zadaneho jmena
        /// </summary>
        /// <param name="filmName"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmData(String filmName)
        {
            return getFilmDataFromLink(getFilmPage(filmName));
        }

        /// <summary>
        /// Nacte udaje o filmu podle zadane adresy
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmDataFromLink(String address)
        {
            if (string.IsNullOrEmpty(address)) return null;

            // Prejit na stranku konkretniho filmu
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.UseProxy)
            {
                if (!SettingsManager.Instance.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.ProxyPort);
                    client.Proxy = proxy;
                }
                else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }

            byte[] data;
            try
            {
                data = client.DownloadData(address);
            }
            catch (Exception)
            {
                return null;
            }
            String readData = client.Encoding.GetString(data);

            // Prevest HTML stranku na XML
            XmlDocument document = convertHtmlToXml(readData);

            return loadDataFromXML(document, address);
        }

        /// <summary>
        /// Nacte z XML dokumentu udaje o filmu
        /// </summary>
        /// <param name="document"></param>
        /// <param name="linkToFilmPage"></param>
        /// <returns></returns>
        private MovieDataStore12 loadDataFromXML(XmlDocument document, String linkToFilmPage)
        {
            if (document != null)
            {
                MovieDataStore12 dataStore = new MovieDataStore12();
                dataStore.link = linkToFilmPage;

                // Hodnoceni
                XmlNodeList list = document.SelectNodes(HODNOCENI_XPATH);
                if (list != null && list.Count > 0)
                {
                    dataStore.imdbRating = list[0].FirstChild.Value;
                    
                    if (dataStore.imdbRating != null && dataStore.imdbRating.Contains("/"))
                    {
                        dataStore.imdbRating = dataStore.imdbRating.Trim();
                    }
                    else
                    {
                        dataStore.imdbRating = "N/A";
                    }
                } else
                {
                    dataStore.imdbRating = "N/A";
                }

                return dataStore;
            }
            return null;
        }

        /// <summary>
        /// Prevede HTML kod na XML
        /// </summary>
        /// <returns></returns>
        private XmlDocument convertHtmlToXml(String readData)
        {
            String tempDir = Environment.GetEnvironmentVariable("TEMP");
            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.GetEnvironmentVariable("TMP");
            }

            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.SpecialFolder.ApplicationData.ToString();
            }

            HtmlAgilityPack.HtmlDocument htmlDocument = new HtmlAgilityPack.HtmlDocument();
            htmlDocument.LoadHtml(readData);
            htmlDocument.OptionOutputAsXml = true;

            htmlDocument.Save(tempDir + "//temp.xml", Encoding.UTF8);

            XmlDocument document = new XmlDocument();
            document.Load(tempDir + "//temp.xml");
            File.Delete(tempDir + "//temp.xml");

            return document;
        }

        #endregion
    }
}